﻿/**
 *
 * 版权：C.c 版权所有
 *
 * 作者：C.c
 *
 * 版本：1.0
 *
 * 创建日期：2017/11/02
 *
 * 描述：资源管理
 *
 * 修订历史：
 *
 */

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace XHFrame
{
    /// <summary>
    /// 资源信息
    /// </summary>
    public class AssetInfo
    {
        private UnityEngine.Object _object;
        public Type AssetType { get; set; }
        public string Path { get; set; }
        public int RefCount { get; set; }

        public bool IsLoaded
        {
            get
            {
                return null != _object;
            }
        }

        public UnityEngine.Object AssetObject
        {
            get
            {
                if (null == _object)
                    _object = Resources.Load(Path);
                return _object;
            }
        }

        /// <summary>
        /// 计时加载
        /// </summary>
        /// <param name="_loaded"></param>
        /// <returns></returns>
        public IEnumerator GetCoroutineObject(Action<UnityEngine.Object> _loaded)
        {
            while (true)
            {
                yield return null;
                if (null == _object)
                {
                    ResourcesLoad();
                    yield return null;

                }
                if (null != _loaded)
                {
                    _loaded(_object);
                }
                yield break;
            }

        }
        Debuger log = null;
        private void ResourcesLoad()
        {
            log = Debuger.GetLogger(typeof(AssetInfo));
            try
            {
                _object = Resources.Load(Path);
                if (null == _object)
                {
                    Debug.Log("Resources Load Failure! Path:" + Path);
                    log.L("Resources Load Failure! Path:" + Path);
                }
            }
            catch (Exception e)
            {
                Debug.LogWarning(e.ToString());
                log.E(e.ToString());
                throw;
            }
        }


        /// <summary>
        /// 异步加载
        /// </summary>
        /// <param name="_loaded"></param>
        /// <returns></returns>
        public IEnumerator GetAsyncObject(Action<UnityEngine.Object> _loaded)
        {
            return GetAsyncObject(_loaded, null);
        }

        /// <summary>
        /// 异步加载
        /// </summary>
        /// <param name="_loaded"></param>
        /// <param name="_progress"></param>
        /// <returns></returns>
        public IEnumerator GetAsyncObject(Action<UnityEngine.Object> _loaded, Action<float> _progress)
        {
            if (null != _object)
            {
                _loaded(_object);
                yield break;
            }

            ResourceRequest _resRequest = Resources.LoadAsync(Path);

            while (_resRequest.progress < 0.9)
            {
                if (null != _progress)
                {
                    _progress(_resRequest.progress);
                    yield return null;
                }
            }
            while (!_resRequest.isDone)
            {
                if (null != _progress)
                    _progress(_resRequest.progress);
                yield return null;
            }
            _object = _resRequest.asset;
            if (null != _loaded)
            {
                _loaded(_object);
            }
            yield return _resRequest;
        }
    }


    /// <summary>
    /// 资源管理
    /// </summary>
    public class ResourcesManager : Singleton<ResourcesManager>
    {

        private Dictionary<string, AssetInfo> dicAssetInfo = null;
        private Debuger log = null;

        public override void Init()
        {
            base.Init();
            dicAssetInfo = new Dictionary<string, AssetInfo>();
            log = Debuger.GetLogger(typeof(ResourcesManager));
        }

        #region load 加载 Resources(资源) 和  Instantiate Object (实例对象)
        /// <summary>
        /// 加载实例
        /// </summary>
        /// <param name="_Path"></param>
        /// <returns></returns>
        public UnityEngine.Object LoadInstance(string _Path)
        {
            UnityEngine.Object _obj = Load(_Path);
            return Instantiate(_obj);
        }
        /// <summary>
        /// 协程加载实例
        /// </summary>
        /// <param name="_Path"></param>
        /// <param name="_Loaded"></param>
        public void LoadCoroutineInstance(string _Path, Action<UnityEngine.Object> _Loaded)
        {
            LoadCoroutine(_Path, (_obj) => { Instantiate(_obj, _Loaded); });
        }

        /// <summary>
        /// 异步加载实例
        /// </summary>
        /// <param name="_Path"></param>
        /// <param name="_Loaded"></param>
        public void LoadAsyncInstance(string _Path, Action<UnityEngine.Object> _Loaded)
        {
            LoadAsset(_Path, (_obj) => { Instantiate(_obj, _Loaded); });
        }
        /// <summary>
        /// 异步加载实例
        /// </summary>
        /// <param name="_Path"></param>
        /// <param name="_Loaded"></param>
        /// <param name="_Progress"></param>
        public void LoadAsyncInstance(string _Path, Action<UnityEngine.Object> _Loaded, Action<float> _Progress)
        {
            LoadAsset(_Path, (_obj) => { Instantiate(_obj, _Loaded); }, _Progress);
        }
        #endregion

        #region load Resources(加载资源)
        /// <summary>
        /// 加载
        /// </summary>
        /// <param name="_Path"></param>
        /// <returns></returns>
        public UnityEngine.Object Load(string _Path)
        {
            AssetInfo _assetInfor = GetAssetInfo(_Path);
            if (null != _assetInfor)
                return _assetInfor.AssetObject;
            return null;
        }
        #endregion

        #region Load Coroutine Resources (加载协程资源)
        /// <summary>
        /// 携程加载资源
        /// </summary>
        /// <param name="_Path"></param>
        /// <param name="_Loader"></param>
        public void LoadCoroutine(string _Path, Action<UnityEngine.Object> _Loader)
        {
            AssetInfo _assetInfo = GetAssetInfo(_Path, _Loader);
            if (null != _assetInfo)
            {
                CoroutineController.Instance.StartCoroutine(_assetInfo.GetCoroutineObject(_Loader));
            }
        }

        #endregion

        #region Load Async Resources (加载异步资源)
        /// <summary>
        /// 加载异步资源
        /// </summary>
        /// <param name="_Path"></param>
        /// <param name="_Loaded"></param>
        public void LoadAsset(string _Path, Action<UnityEngine.Object> _Loaded)
        {
            LoadAsset(_Path, _Loaded, null);
        }

        /// <summary>
        /// 加载异步资源
        /// </summary>
        /// <param name="_Path"></param>
        /// <param name="_Loaded"></param>
        /// <param name="_Proeress"></param>
        public void LoadAsset(string _Path, Action<UnityEngine.Object> _Loaded, Action<float> _Proeress)
        {
            AssetInfo _assetInfo = GetAssetInfo(_Path, _Loaded);
            if (_assetInfo != null)
            {
                CoroutineController.Instance.StartCoroutine(_assetInfo.GetAsyncObject(_Loaded, _Proeress));
            }
        }
        #endregion

        #region Get AssetInfo & Instantiate Object (返回资源信息实例对象)

        // 返回资源信息
        private AssetInfo GetAssetInfo(string _Path)
        {
            return GetAssetInfo(_Path, null);
        }

        // 返回资源信息
        private AssetInfo GetAssetInfo(string _Path, Action<UnityEngine.Object> _Loaded)
        {
            if (string.IsNullOrEmpty(_Path))
            {
                Debug.LogError("Error:null _path name");
                log.E("Error:null _path name");
                if (null != _Loaded)
                    _Loaded(null);
            }
            AssetInfo _assetInfo = null;
            if (!dicAssetInfo.TryGetValue(_Path, out _assetInfo))
            {
                _assetInfo = new AssetInfo();
                _assetInfo.Path = _Path;
                dicAssetInfo.Add(_Path, _assetInfo);
            }
            _assetInfo.RefCount++;
            return _assetInfo;
        }

        // 实例
        private UnityEngine.Object Instantiate(UnityEngine.Object _obj)
        {
            return Instantiate(_obj, null);
        }

        // 实例
        private UnityEngine.Object Instantiate(UnityEngine.Object _obj, Action<UnityEngine.Object> _Loaded)
        {
            UnityEngine.Object _retObj = null;
            if (_obj != null)
            {
                _retObj = MonoBehaviour.Instantiate(_obj);
                if (_retObj != null)
                {
                    if (null != _Loaded)
                    {
                        _Loaded(_retObj);
                        return null;
                    }
                    return _retObj;
                }
                else
                {
                    Debug.LogError("Error : null  Instantiate _retObj");
                    log.E("Error : null  Instantiate _retObj");
                    return null;
                }
            }
            else
            {
                Debug.LogError("Error : null Resources Load Return _obj");
                log.E("Error : null Resources Load Return _obj");
                return null;
            }
        }
        #endregion

    }
}
